import RNFS from 'react-native-fs';

import Log from '../../../common/log';
import { isIOS } from '../../../constant';
import customAwait from '../../../util/customAwait';
import audioFile from '../../../util/native/audioFile';
import rnfsDownload from '../../../util/videoDownload/rnfsDownload';

const TAG = 'SpliceAudio';
const DOWNLOAD_AUDIO_PATH = `${
  isIOS ? RNFS.DocumentDirectoryPath : RNFS.ExternalDirectoryPath
}/videos/audio`;

const downloadAudio = (url: string): Promise<string> =>
  new Promise(
    async (resolve, reject): Promise<void> => {
      const list = url.split('/');
      if (
        url.indexOf('http') === -1 ||
        url.indexOf('mp3') === -1 ||
        list.length < 2
      ) {
        reject(new Error(`invalid url : ${url}`));
        Log.e(
          TAG,
          JSON.stringify({
            event: 'invalid url',
            url
          })
        );
        return;
      }

      const fileName = list[list.length - 1];

      const fileUrl = `${DOWNLOAD_AUDIO_PATH}/${fileName}`;
      const options = {
        fromUrl: url,
        toFile: fileUrl,
        background: true,
        connectionTimeout: 8000,
        readTimeout: 8000
      };
      const ret = await rnfsDownload(options);
      const [error, res] = await customAwait(ret.promise);
      if (error || !res) {
        Log.e(
          TAG,
          JSON.stringify({
            event: 'audioDownloadFail',
            url,
            error
          })
        );
        reject(error);
        return;
      }

      const { statusCode } = res;
      if (statusCode !== 200) {
        Log.e(
          TAG,
          JSON.stringify({
            event: 'audioDownloadFail',
            url,
            statusCode
          })
        );
        reject(statusCode);
        return;
      }

      Log.i(
        TAG,
        JSON.stringify({
          event: 'audioDownloadSuccess',
          url
        })
      );
      resolve(fileUrl);
    }
  );

interface SpliceAudioRes {
  audioUrl: string;
  audioFilePath: string;
  duration: number;
}

export const spliceAudio = (urlList: string[]): Promise<SpliceAudioRes> =>
  new Promise(
    async (resolve, reject): Promise<void> => {
      let fileUrlList: string[] = [];
      let downloadError;
      for (let i = 0; i < urlList.length; i += 1) {
        const url = urlList[i];
        // eslint-disable-next-line no-await-in-loop
        const [error, fileUrl] = await customAwait(downloadAudio(url));
        if (error || !fileUrl) {
          downloadError = error;
          break;
        }
        // eslint-disable-next-line no-await-in-loop
        const [statError, statRes] = await customAwait(RNFS.stat(fileUrl));
        if (statRes) {
          const { size } = statRes;
          if (Number(size) === 0) {
            downloadError = `${url} is not valid`;
            break;
          }
        }
        fileUrlList = [...fileUrlList, fileUrl];
      }
      if (downloadError) {
        Log.e(
          TAG,
          JSON.stringify({
            event: 'spliceAudio download error : ',
            downloadError
          })
        );
        reject(downloadError);
        return;
      }
      const content = String(new Date().getTime());
      const outFilePath = `${DOWNLOAD_AUDIO_PATH}/${content}.wav`;
      const [error, res] = await customAwait(
        audioFile.asyncConcatAudioFiles(fileUrlList, outFilePath)
      );

      for (let i = 0; i < fileUrlList.length; i += 1) {
        const fileUrl = fileUrlList[i];
        RNFS.unlink(fileUrl);
      }

      if (error) {
        Log.e(
          TAG,
          JSON.stringify({
            event: 'spliceAudio concat error : ',
            error
          })
        );
        reject(error);
        return;
      }
      if (!res) {
        Log.e(
          TAG,
          JSON.stringify({
            event: 'spliceAudio success with empty res : ',
            res
          })
        );
        RNFS.unlink(outFilePath);
        reject(new Error('audio is empty'));
        return;
      }
      const audioUrl = `http://127.0.0.1:21994/videos/audio/${content}.wav`;
      const { duration = 0 } = res as { duration: number };
      resolve({
        audioFilePath: outFilePath,
        audioUrl,
        duration
      });
    }
  );

export const deleteAudio = (path: string): void => {
  RNFS.unlink(path);
};
